/*
 * RED5 HLS plugin - https://github.com/mondain/red5-hls-plugin
 * 
 * Copyright 2006-2013 by respective authors (see below). All rights reserved.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.red5.xuggler.reader;

import java.awt.image.BufferedImage;
import java.util.concurrent.TimeUnit;

import org.bytedeco.javacv.FFmpegFrameGrabber;
import org.bytedeco.javacv.Frame;
import org.bytedeco.javacv.Java2DFrameConverter;
import org.red5.service.httpstream.SegmentFacade;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.xuggle.mediatool.IMediaReader;
import com.xuggle.mediatool.event.IAudioSamplesEvent;
import com.xuggle.mediatool.event.ICloseEvent;
import com.xuggle.mediatool.event.IVideoPictureEvent;

/**
 * Reads media data from an RTMP source.
 * 
 * @author Paul Gregoire (mondain@gmail.com)
 */
public class RTMPReader  implements GenericReader {

	private Logger log = LoggerFactory.getLogger(RTMPReader.class);

	private IMediaReader reader;
	FFmpegFrameGrabber  grabber;
	private String inputUrl;

	private int inputWidth;

	private int inputHeight;

	private int inputSampleRate;

	private int inputChannels;

	private boolean audioEnabled = true;

	private boolean videoEnabled = true;

	private boolean keyFrameReceived;

	// time at which we started reading
	private long startTime;

	// total samples read
	private volatile long audioSamplesRead;

	// total frames read
	private volatile long videoFramesRead;

	private boolean closed = true;

	private SegmentFacade facade;
	
	public RTMPReader() {
	}

	public RTMPReader(String url) {
		inputUrl = url;
	}

	public void init(SegmentFacade facade) throws Exception {
		log.debug("Input url: {}", inputUrl);
		this.facade = facade;
		grabber = FFmpegFrameGrabber.createDefault(inputUrl);
		 
		/*
         * "timeout" - IS IGNORED when a network cable have been unplugged
         * before a connection and sometimes when connection is lost.
         *
         * "rw_timeout" - IS IGNORED when a network cable have been
         * unplugged before a connection but the option takes effect after a
         * connection was established. 
         * "stimeout" - works fine.
         */
		//grabber.setOption(TimeoutOption.STIMEOUT.key(),String.valueOf(stimeOut * 1000000));
		//grabber.setOption("rtsp_transport", "tcp");
		// -map指定哪些流做为输入， 0:0 表示第0个输入文件的第0个流
//		grabber.setOption("map","0:0"); 
		grabber.setFrameRate(20); 
 		grabber.setImageWidth(facade.outputWidth);
 	 	grabber.setImageHeight(facade.outputHeight); 
	 	grabber.start();
	}

	public void stop() {
		try {
			grabber.release();
			grabber.close();
		} catch (Exception e) {
			 
			e.printStackTrace();
		}
		
	}
	Java2DFrameConverter converter = new Java2DFrameConverter();
	public void run() {
		log.debug("RTMPReader - run");
		// read and decode packets from the source
		log.trace("Starting reader loop");

		//		IContainer container = reader.getContainer();
		//		IPacket packet = IPacket.make();
		//      while (container.readNextPacket(packet) >= 0 && !packet.isKeyPacket()) {
		//			log.debug("Looking for key packet..");        	
		//      }
		//      packet.delete(); 
		// error holder
		Frame err = null;
		try {
			long startTime=0;
			long videoTS=0; 
			// packet read loop 
			while ((err = grabber.grabFrame()) != null) { 
				if (startTime == 0) {
					startTime = System.currentTimeMillis();
				}   
				videoTS = 1000 * ( System.currentTimeMillis() - startTime);
				BufferedImage bImg = converter.convert(err);
				if(bImg == null) {
					continue;
				}
				facade.queueVideo(bImg,videoTS, TimeUnit.NANOSECONDS); 
			}
		} catch (Throwable t) {
			log.warn("Exception closing reader", t);
		}
		if (err != null) {
			log.warn("{}", err.toString());
		}
		log.trace("End of reader loop");
		stop();
		log.trace("RTMPReader - end");
	}

	 
	public void onAudioSamples(IAudioSamplesEvent event) { 
		 
	}

	 
	public void onVideoPicture(IVideoPictureEvent event) {
		 
	}

	 
	public void onClose(ICloseEvent event) {
		 
	}

	public String getInputUrl() {
		return inputUrl;
	}

	public void setInputUrl(String inputUrl) {
		this.inputUrl = inputUrl;
	}

	/**
	 * @return the inputWidth
	 */
	public int getInputWidth() {
		return inputWidth;
	}

	/**
	 * @return the inputHeight
	 */
	public int getInputHeight() {
		return inputHeight;
	}

	/**
	 * @return the inputSampleRate
	 */
	public int getInputSampleRate() {
		return inputSampleRate;
	}

	/**
	 * @return the inputChannels
	 */
	public int getInputChannels() {
		return inputChannels;
	}

	/**
	 * @return the reader
	 */
	public IMediaReader getReader() {
		return reader;
	}

	/**
	 */
	public void disableAudio() {
		this.audioEnabled = false;
	}

	/**
	 */
	public void disableVideo() {
		this.videoEnabled = false;
	}

	/**
	 * @return the audioEnabled
	 */
	public boolean isAudioEnabled() {
		return audioEnabled;
	}

	/**
	 * @return the videoEnabled
	 */
	public boolean isVideoEnabled() {
		return videoEnabled;
	}

	/**
	 * Returns whether or not the reader is closed.
	 * 
	 * @return true if closed or reader does not exist
	 */
	public boolean isClosed() {
		return closed;
	}

	/**
	 * Returns true if data has been read from the source.
	 * 
	 * @return
	 */
	public boolean hasReadData() {
		return audioSamplesRead > 0 || videoFramesRead > 0;
	}

	/**
	 * @return the keyFrameReceived
	 */
	public boolean isKeyFrameReceived() {
		return keyFrameReceived;
	}

	@Override
	public void init() throws Exception {
		// TODO Auto-generated method stub
		
	} 

}
